home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Language/OS - Multiplatform Resource Library
/
LANGUAGE OS.iso
/
lisp
/
kcl
/
akcl
/
akcl1615.lha
/
c
/
sfasl.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-04-07
|
19KB
|
777 lines
/*
Copyright William Schelter. All rights reserved.
There is a companion file rsym.c which is used to build
a list of the external symbols in a COFF or A.OUT object file, for
example saved_kcl. These are loaded into kcl, and the
linking is done directly inside kcl. This saves a good
deal of time. For example a tiny file foo.o with one definition
can be loaded in .04 seconds. This is much faster than
previously possible in kcl.
The function fasload from unixfasl.c is replaced by the fasload
in this file.
this file is included in unixfasl.c
via #include "../c/sfasl.c"
*/
/* for testing in standalone manner define STAND
You may then compile this file cc -g -DSTAND -DDEBUG -I../hn
a.out /tmp/foo.o /public/akcl/unixport/saved_kcl /public/akcl/unixport/
will write a /tmp/sfasltest file
which you can use comp to compare with one produced by ld.
*/
#define IN_SFASL
#ifdef STAND
#include "config.h"
#include <stdio.h>
#include "mdefs.h"
#else
#include "include.h"
#undef S_DATA
#endif
#include <varargs.h>
#include "ext_sym.h"
struct node * find_sym();
int node_compare();
char *malloc();
char *the_start;
char *bsearch();
struct reloc relocation_info;
/* next 5 static after debug */
int debug;
#ifdef DEBUG
#define debug sfasldebug
int sfasldebug=0;
#define dprintf(s,ar) if(debug) { printf(" ( s )",ar) ; fflush(stdout);}
#define STAT
#else /* end debug */
#define dprintf(s,ar)
#define STAT static
#endif
#define MAXPATHLEN 200
#define PTABLE_EXTRA 20
STAT struct syment *symbol_table;
STAT char *start_address;
STAT char *my_string_table;
STAT int extra_bss;
STAT char command[200];
STAT char tmpfile1 [50];
#ifndef describe_sym
#define describe_sym(a)
#endif
#ifdef STAND
#include "rel_stand.c"
#endif
#define TEMPSPACE 50000
char tempspace[TEMPSPACE];
char *bil;
char
*temp_malloc(n)
unsigned int n;
{char *val;
val=(char *) (4*((((int)bil)+4)/4));
bil=val+n;
if (bil < tempspace +TEMPSPACE)
return val;
else {bil=val;
dprintf( having to use regular malloc for %d,n);
return malloc(n);}
}
/* begin reloc_file */
#include RELOC_FILE
/* end reloc_file */
/* free up space which is not allocated in tempspace */
#define TEMP_FREE(x) \
if (((char *)x)> tempspace+TEMPSPACE || ((char *)x)< tempspace) \
free(x)
int
fasload(faslfile)
object faslfile;
{ long fasl_vector_start;
struct filehdr fileheader;
#ifdef COFF
struct scnhdr sectionheader;
struct scnhdr section[10];
struct aouthdr header;
#endif
int textsize, datasize, bsssize,nsyms;
int string_size=0;
object memory, data;
FILE *fp;
char filename[MAXPATHLEN];
int i;
int init_address=0;
#ifndef STAND
object *old_vs_base = vs_base;
object *old_vs_top = vs_top;
#endif
bil=tempspace; /* reset tmp malloc */
extra_bss=0;
#ifdef STAND
strcpy(filename,faslfile);
fp=fopen(filename,RDONLY);
#else
coerce_to_filename(faslfile, filename);
faslfile = open_stream(faslfile, smm_input, Cnil, Kerror);
vs_push(faslfile);
fp = faslfile->sm.sm_fp;
#endif
HEADER_SEEK(fp);
if(!fread((char *)&fileheader, sizeof(struct filehdr), 1, fp))
FEerror("Could not get the header",0,0);
nsyms = NSYMS(fileheader);
#ifdef COFF
#ifdef AIX3
setup_for_aix_load();
#endif
fread(&header,1,fileheader.f_opthdr,fp);
fread(§ion[1],fileheader.f_nscns,sizeof (struct scnhdr),fp);
textsize = section[TEXT_NSCN].s_size;
datasize = section[DATA_NSCN].s_size;
if (strcmp(section[BSS_NSCN].s_name, ".bss") == 0)
bsssize=section[BSS_NSCN].s_size;
else bsssize=section[BSS_NSCN].s_size = 0;
#endif
#ifdef BSD
textsize=fileheader.a_text;
datasize=fileheader.a_data;
bsssize=fileheader.a_bss;
#endif
symbol_table =
(struct syment *) temp_malloc(sizeof(struct syment)*
(unsigned int)nsyms);
fseek(fp,(int)( N_SYMOFF(fileheader)), 0);
{
for (i = 0; i < nsyms; i++)
{fread((char *)&symbol_table[i], SYMESZ, 1, fp);
dprintf( symbol table %d , i);
if (debug) describe_sym(i);
dprintf( at %d , &symbol_table[i]);
#ifdef HPUX
symbol_table[i].n_un.n_strx = string_size;
dprintf(string_size %d, string_size);
string_size += symbol_table[i].n_length + 1;
fseek(fp,(int)symbol_table[i].n_length,1);
#endif
}
}
/*
on MP386
The sizeof(struct syment) = 20, while only SYMESZ =18. So we had to read
one at a time.
fread((char *)symbol_table, SYMESZ*fileheader.f_nsyms,1,fp);
*/
#ifdef READ_IN_STRING_TABLE
my_string_table=READ_IN_STRING_TABLE(fp,string_size);
#else
#ifdef MUST_SEEK_TO_STROFF
fseek(fp,N_STROFF(fileheader),0);
#endif
{int ii=0;
if (!fread((char *)&ii,sizeof(int),1,fp))
{FEerror("The string table of this file did not have any length",0,
0);}
fseek(fp,-4,1);
/* at present the string table is located just after the symbols */
my_string_table=temp_malloc((unsigned int)ii);
dprintf( string table leng = %d, ii);
if(ii!=fread(my_string_table,1,ii,fp))
FEerror("Could not read whole string table",0,0) ;
}
#endif
#ifdef SEEK_TO_END_OFILE
SEEK_TO_END_OFILE(fp);
#else
while ((i = getc(fp)) == 0)
;
ungetc(i, fp);
#endif
fasl_vector_start=ftell(fp);
if (!((c_table.ptable) && *(c_table.ptable)))
build_symbol_table();
/* figure out if there is more bss space needed */
extra_bss=get_extra_bss(symbol_table,nsyms,datasize+textsize+bsssize,
&init_address,bsssize);
/* allocate some memory */
#ifndef STAND
memory = alloc_object(t_cfdata);
memory->cfd.cfd_self = 0;
memory->cfd.cfd_start = 0;
memory->cfd.cfd_size = datasize+textsize+bsssize + extra_bss;
vs_push(memory);
the_start=start_address=
memory->cfd.cfd_start =
alloc_contblock(memory->cfd.cfd_size);
#else
the_start=start_address
= malloc(datasize+textsize+bsssize + extra_bss + 0x80000);
the_start=start_address= (char *)(
0x1000* ((((int)the_start + 0x70000) + 0x1000)/0x1000));
#endif
dprintf( code size %d , datasize+textsize+bsssize + extra_bss);
if (fseek(fp,N_TXTOFF(fileheader) ,0) < 0)
FEerror("file seek error",0,0);
fread(the_start, textsize + datasize, 1, fp);
dprintf(read into memory text +data %d bytes, textsize + datasize);
/* relocate the actual loaded text */
dprintf( the_start %x, the_start);
/* record which symbols are used */
#ifdef SYM_USED
{int j=0;
for(j=1; j< BSS_NSCN ; j++)
{ dprintf( relocating section %d \n,j);
if (section[j].s_nreloc) fseek(fp,section[j].s_relptr,0);
for(i=0; i < section[j].s_nreloc; i++)
{ struct syment *sym;
fread(&relocation_info, RELSZ, 1, fp);
sym = & symbol_table[relocation_info.r_symndx];
if (TC_SYMBOL_P(sym))
SYM_USED(sym) = 1;
}}}
#endif
/* this looks up symbols in c.ptable and also adds new externals to
that c.table */
relocate_symbols(NSYMS(fileheader));
#ifdef COFF
{int j=0;
for(j=1; j< BSS_NSCN ; j++)
{ dprintf( relocating section %d \n,j);
if (section[j].s_nreloc) fseek(fp,section[j].s_relptr,0);
for(i=0; i < section[j].s_nreloc; i++)
/* RELSZ = sizeof(relocation_info) */
{fread(&relocation_info, RELSZ, 1, fp);
dprintf(relocating %d,i);
relocate();};
}};
#endif
#ifdef BSD
fseek(fp,N_RELOFF(fileheader),0);
{int nrel = (fileheader.a_trsize/sizeof(struct reloc));
for (i=0; i < nrel; i++)
{fread((char *)&relocation_info, sizeof(struct reloc),
1, fp);
dprintf(relocating %d,i);
relocate();
}
}
#ifdef N_DRELOFF
fseek (fp, N_DRELOFF(fileheader), 0);
#endif
{int nrel = (fileheader.a_drsize/sizeof(struct reloc));
the_start += fileheader.a_text;
for (i=0; i < nrel; i++)
{fread((char *)&relocation_info, sizeof(struct reloc),
1, fp);
dprintf(relocating %d,i);
relocate();
}
}
#endif
/* end of relocation */
dprintf( END OF RELOCATION \n,0);
dprintf( invoking init function at %x, start_address)
dprintf( textsize is %x,textsize);
dprintf( datasize is %x,datasize);
/* read in the fasl vector */
fseek(fp,fasl_vector_start,0);
if (feof(fp))
{data=0;}
else{
data = read_fasl_vector(faslfile);
vs_push(data);
#ifdef COFF
dprintf( read fasl now symbols %d , fileheader.f_nsyms);
#endif
}
close_stream(faslfile, 1);
/*
{
int fd;
fd = creat ("xsakcl.bits", 0777);
write (fd, memory->cfd.cfd_start, textsize + datasize);
close (fd);
fd = open ("xsl2.bits", 0);
read (fd, memory->cfd.cfd_start, memory->cfd.cfd_size);
close (fd);
}
*/
#ifndef STAND
TEMP_FREE(my_string_table);
TEMP_FREE(symbol_table);
#ifdef CLEAR_CACHE
CLEAR_CACHE;
#endif
call_init(init_address,memory,data);
vs_base = old_vs_base;
vs_top = old_vs_top;
if(symbol_value(Vload_verbose)!=Cnil)
printf("start address -T %x ",memory->cfd.cfd_start);
return(memory->cfd.cfd_size);
#endif
{FILE *out;
out=fopen("/tmp/sfasltest","w");
fwrite((char *)&fileheader, sizeof(struct filehdr), 1, out);
fwrite(start_address,sizeof(char),datasize+textsize,out);
fclose(out);}
printf("\n(start %x)\n",start_address);
}
#ifdef AIX3
struct syment *
get_symbol(name,scnum,symbol_table,length)
char *name;
int scnum,length;
struct syment *symbol_table;
{ struct syment *end,*sym;
char tem[SYMNMLEN +1];
char *na;
end =symbol_table + length;
for(sym=symbol_table; sym < end; sym += (NUM_AUX(sym) +1))
{if ((sym)->n_scnum == scnum)
{ na=SYM_NAME(sym);
if (strcmp(name,na) == 0)
{return sym;}}}
return 0;}
#endif /* aix3 */
struct node *
find_sym(sym,name)
struct syment *sym;
char *name;
{ char tem[SYMNMLEN +1];
tem [SYMNMLEN] = 0;
if (name==0) name = SYM_NAME(sym);
{struct node joe,*answ;
joe.string=name;
answ = (struct node *) bsearch((char *)(&joe),(char*) (c_table.ptable),
c_table.length,
sizeof(struct node), node_compare);
return answ;
}}
get_extra_bss(symbol_table,length,start,ptr,bsssize)
int length,bsssize;
struct syment *symbol_table;
int *ptr; /* store init address offset here */
{int result = start;
int next_bss = start - bsssize;
struct syment *end,*sym;
char tem[SYMNMLEN +1];
end =symbol_table + length;
for(sym=symbol_table; sym < end; sym++)
{
#ifdef FIND_INIT
FIND_INIT
#endif
#ifdef AIX3
/* we later go through the relocation entries making this 1
for symbols used */
#ifdef SYM_USED
if(TC_SYMBOL_P(sym))
{SYM_USED(sym) = 0;}
#endif
/* fix up the external refer to _ptrgl to be local ref */
if (sym->n_scnum == 0 &&
strcmp(sym->n_name,"_ptrgl")==0)
{struct syment* s =
get_symbol("._ptrgl",TEXT_NSCN,symbol_table,length);
if (s ==0) FEerror("bad glue",0);
sym->n_value = next_bss ;
ptrgl_offset = next_bss;
ptrgl_text = s->n_value;
next_bss += 0xc;
sym->n_scnum = DATA_NSCN;
((union auxent *)(sym+1))->x_csect.x_scnlen = 0xc;
}
if(sym->n_scnum != BSS_NSCN) goto NEXT;
if(SYM_EXTERNAL_P(sym))
{int val=sym->n_value;
struct node joe;
if (val && c_table.ptable)
{struct node *answ;
answ= find_sym(sym,0);
if(answ)
{sym->n_value = answ->address ;
sym->n_scnum = N_UNDEF;
val= ((union auxent *)(sym+1))->x_csect.x_scnlen;
result -= val;
goto NEXT;
}}
}
/* reallocate the bss space */
if (sym->n_value == 0)
{result += ((union auxent *)(sym+1))->x_csect.x_scnlen;}
sym->n_value = next_bss;
next_bss += ((union auxent *)(sym+1))->x_csect.x_scnlen;
NEXT:
;
/* end aix3 */
#endif
#ifdef BSD
tem; /* ignored */
if(SYM_EXTERNAL_P(sym) && SYM_UNDEF_P(sym))
#endif
#ifdef COFF
if(0)
/* what we really want is
if (sym->n_scnum==0 && sym->n_sclass == C_EXT
&& !(bsearch(..in ptable for this symbol)))
Since this won't allow loading in of a new external array
char foo[10] not ok
static foo[10] ok.
for the moment we give undefined symbol warning..
Should really go through the symbols, recording the external addr
for ones found in ptable, and for the ones not in ptable
set some flag, and add up the extra_bss required. Then
when you have the new memory chunk in hand,
you could make the pass setting the relative addresses.
for the ones you flagged last time.
*/
#endif
/* external bss so not included in size of bss for file */
{int val=sym->n_value;
if (val && c_table.ptable
&& (0== find_sym(sym,0)))
{ sym->n_value=result;
result += val;}}
sym += NUM_AUX(sym);
}
return (result-start);
}
/* go through the symbol table changing the addresses of the symbols
to reflect the current cfd_start */
relocate_symbols(length)
unsigned int length;
{struct syment *end,*sym;
unsigned int typ;
char *str;
char tem[SYMNMLEN +1];
tem[SYMNMLEN]=0;
end =symbol_table + length;
for(sym=symbol_table; sym < end; sym++) {
typ=NTYPE(sym);
#ifdef BSD
#ifdef N_STAB
if (N_STAB & sym->n_type) continue;/* skip: It is for dbx only */
#endif
typ=N_SECTION(sym);
/* if(sym->n_type & N_EXT) should add the symbol name,
so it would be accessible by future loads */
#endif
switch (typ) {
#ifdef BSD
case N_ABS : case N_TEXT: case N_DATA: case N_BSS:
#endif
#ifdef COFF
case TEXT_NSCN : case DATA_NSCN: case BSS_NSCN :
#endif
str=SYM_NAME(sym);
dprintf( for sym %s ,str)
dprintf( new value will be start %x, start_address);
#ifdef AIX3
if(N_SECTION(sym) == DATA_NSCN
&& NUM_AUX(sym)
&& allocate_toc(sym))
break;
#endif
sym->n_value = (int)start_address;
break;
case N_UNDEF:
str=SYM_NAME(sym);
dprintf( undef symbol %s ,str);
dprintf( symbol diff %d , sym - symbol_table);
describe_sym(sym-symbol_table);
set_symbol_address(sym,str);
describe_sym(sym-symbol_table);
break;
default:
#ifdef COFF
dprintf(am ignoring a scnum %d,(sym->n_scnum));
#endif
break;
}
sym += NUM_AUX(sym);
}
}
/*
STEPS:
1) read in the symbol table from the file,
2) go through the symbol table, relocating external entries.
3) for i <=2 go thru the relocation information for this section
relocating the text.
4) done.
*/
set_symbol_address(sym,string)
struct syment *sym;
char *string;
{struct node *answ;
if (c_table.ptable)
{
dprintf(string %s, string);
answ = find_sym(sym,string);
dprintf(answ %d , (answ ? answ->address : -1));
if(answ)
{
#ifdef COFF
#ifdef _AIX370
if (NTYPE(sym) == N_UNDEF)
sym->n_value = answ->address;
else
#endif
sym->n_value = answ->address -sym->n_value;
/* for symbols in the local data,text and bss this gets added
on when we add the current value */
#endif
#ifdef BSD
/* the old value of sym->n_value is the length of the common area
starting at this address */
sym->n_value = answ->address;
#endif
#ifdef AIX3
fix_undef_toc_address(answ,sym,string);
#endif
}
else
{
#ifdef BSD
{char *name;
name=malloc(1+strlen(string));
strcpy(name,string);
sym->n_value = sym->n_value + (unsigned int) the_start;
add_symbol(name,sym->n_value,NULL);
}
#endif
fprintf(stdout,"undefined %s symbol",string)
;fflush(stdout);
}}
else{FEerror("symbol table not loaded",0,0);}}
/*
#define ADD_SYMBOL(name) add_symbol("name",(int) &(name),0)
Use the add_symbol to add a c symbol, which you want to refer
to in subsequent loads. The address used in subsequent loads,
will be the load address of the current symbol.
Such a symbol may only be added once, since subsequent references
will try to link to the old address.
*/
build_symbol_table()
{ printf("Building symbol table for %s ..\n",kcl_self);fflush(stdout);
sprintf(tmpfile1,"rsym%d",getpid());
coerce_to_filename(symbol_value(siVsystem_directory),
system_directory);
#ifndef RSYM_COMMAND
sprintf(command,"%srsym %s %s",system_directory,kcl_self,tmpfile1);
#else
RSYM_COMMAND(command,system_directory,kcl_self,tmpfile1);
#endif
if (system(command) != 0)
FEerror("The rsym command ~a failed .",1,make_simple_string(command)
);
read_special_symbols(tmpfile1);
unlink(tmpfile1);
dprintf(c_table %d , c_table.length);
qsort((char*)(c_table.ptable),(int)(c_table.length),sizeof(struct node),node_compare);
}
/*to do:Addition of one symbol to the ptable is very slow, because we
sort each time! */
add_symbol(va_alist)
va_dcl
{char *string;
int address;
int nstr,i;
va_list ap;
/* terminate arg list with NULL pointer */
if(!(c_table.ptable)) return ; /* this is in a function before ptable is init */
nstr=0;
/* count the number of strings */
va_start(ap);
while (va_arg(ap,char*)!=0)
{ nstr++;
va_arg(ap,int);
if (nstr >1000) FEerror("Did you really give 1000 strings or just forget 0 ending",0,0);};
va_end(ap);
va_start(ap);
if (( int)((c_table.alloc_length) - (c_table.length)) -nstr>0)
{
BEGIN:
for(i=0;i<2*nstr;i=i+2)
{ string=va_arg(ap,char *);
if(find_sym(0,string))
{FEerror("The string ~a is already in the ptable",1,
make_simple_string(string));};
{struct node *u;
u= ((*(c_table.ptable))+((c_table.length)+(i/2)));
u->string = string;
u->address = va_arg(ap,int);}
}
(c_table.length)=(c_table.length)+nstr;
qsort((char*)(c_table.ptable),(int)(c_table.length),sizeof(struct node),node_compare);
}
else
/* grow the ptable */
{ TABL *new, *old_pt;
new=
(TABL *)malloc(sizeof(struct node)
*((c_table.alloc_length)=((c_table.length) + nstr + PTABLE_EXTRA)));
old_pt=(c_table.ptable);
/* copy it */
{register int i ;
for (i=0; i < c_table.length; i++)
{(*new)[i].string=(*old_pt)[i].string;
(*new)[i].address=(*old_pt)[i].address;}}
(c_table.ptable)=new;
free((char *)old_pt);
goto BEGIN ;
}
va_end(ap);
}
/* this is in fat_string.c for the moment */
/*
read_special_symbols(symfile)
char *symfile;
{FILE *symin;
char *symbols;
int i,jj;
struct lsymbol_table tab;
if (!(symin=fopen(symfile,"r")))
{perror(symfile);exit(1);};
fread((char *)&tab,sizeof(tab),1,symin);
symbols=malloc(tab.tot_leng);
c_table.alloc_length=( (PTABLE_EXTRA+ tab.n_symbols));
c_table.ptable =(TABL *)malloc(sizeof(struct node) * (c_table.alloc_length));
if (!(c_table.ptable)) {perror("could not allocate"); exit(1);};
i=0;
c_table.length = tab.n_symbols;
while(i < tab.n_symbols)
{ fread((char *)&jj,sizeof(int),1,symin);
(SYM_ADDRESS(c_table,i))=jj;
SYM_STRING(c_table,i)=symbols;
while( *(symbols++) = getc(symin))
{;}
dprintf( name %s , SYM_STRING(c_table,i));
dprintf( address %d , jj);
i++;
}
}
*/
#ifdef DEBUG
print_name(p)
struct syment *p;
{char tem[10],*name;
name=SYM_NAME(p);
name= (((p)->_n._n_n._n_zeroes == 0) ?
&my_string_table[(p)->_n._n_n._n_offset] :
((p)->_n._n_name[SYMNMLEN -1] ?
(strncpy(tem,(p)->_n._n_name,
SYMNMLEN),
(char *)tem) :
(p)->_n._n_name ));
printf("(name:|%s|)",name);
printf("(sclass 0x%x)",p->n_sclass);
printf("(external_p 0x%x)",SYM_EXTERNAL_P(p));
printf("(n_type 0x%x)",p->n_type);
printf("(n_value 0x%x)",p->n_value);
printf("(numaux 0x%x)\n",NUM_AUX(p));
fflush(stdout);
}
#endif